/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package tls

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"testing"

	"github.com/agiledragon/gomonkey/v2"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
)

type TestSuite struct {
	suite.Suite
	server    http.Server
	rootKEY   string
	rootPEM   string
	rootSRL   string
	serverKEY string
	serverPEM string
	serverCSR string
}

func (s *TestSuite) SetupSuite() {
	certificatePath, err := os.Getwd()
	if err != nil {
		s.T().Errorf("failed to get current working dictionary: %s", err.Error())
		return
	}

	certificatePath += "/../../../test/"
	s.rootKEY = certificatePath + "ca.key"
	s.rootPEM = certificatePath + "ca.crt"
	s.rootSRL = certificatePath + "ca.srl"
	s.serverKEY = certificatePath + "server.key"
	s.serverPEM = certificatePath + "server.crt"
	s.serverCSR = certificatePath + "server.csr"

	body := "Hello"
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "%s", body)
	})

	s.server = http.Server{
		Addr:    "127.0.0.1:6061",
		Handler: handler,
	}
}

func (s *TestSuite) TearDownSuite() {
	s.server.Shutdown(context.Background())

	os.Remove(s.serverKEY)
	os.Remove(s.serverPEM)
	os.Remove(s.serverCSR)
	os.Remove(s.rootKEY)
	os.Remove(s.rootPEM)
	os.Remove(s.rootSRL)
}

func TestOptionTestSuite(t *testing.T) {
	suite.Run(t, new(TestSuite))
}

func TestVerifyCert(t *testing.T) {
	var raw [][]byte
	tlsConfig = &tls.Config{}
	tlsConfig.ClientCAs = x509.NewCertPool()
	err := VerifyCert(raw, nil)
	assert.NotNil(t, err)

	raw = [][]byte{
		[]byte("0"),
		[]byte("1"),
	}
	err = VerifyCert(raw, nil)
	assert.NotNil(t, err)
}

func TestNewTLSConfig(t *testing.T) {
	defaultCertFile := "/home/sn/resource/secret/cert.pem"
	defaultKeyFile := "/home/sn/resource/secret/key.pem"
	p := gomonkey.ApplyFunc(ioutil.ReadFile, func(filename string) ([]byte, error) {
		return nil, nil
	})

	p.ApplyFunc(tls.LoadX509KeyPair, func(certFile, keyFile string) (tls.Certificate, error) {
		return tls.Certificate{}, nil
	})
	defer p.Reset()
	actual := NewTLSConfig(WithRootCAs(DefaultCAFile),
		WithCerts(defaultCertFile, defaultKeyFile), WithSkipVerify())
	expect := &tls.Config{
		MinVersion: tls.VersionTLS12,
		CipherSuites: []uint16{
			// for TLS1.2
			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
			tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
			tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
			// for TLS1.3
			tls.TLS_AES_128_GCM_SHA256,
			tls.TLS_AES_256_GCM_SHA384,
			tls.TLS_CHACHA20_POLY1305_SHA256,
		},
		PreferServerCipherSuites: true,
		Renegotiation:            tls.RenegotiateNever,
		InsecureSkipVerify:       true,
		RootCAs:                  nil,
		Certificates:             []tls.Certificate{{}},
	}

	assert.Equal(t, expect, actual)
}

func TestWithCerts(t *testing.T) {
	defer gomonkey.ApplyFunc(tls.LoadX509KeyPair, func(certFile, keyFile string) (tls.Certificate, error) {
		return tls.Certificate{}, errors.New("LoadX509KeyPair error")
	}).Reset()
	certs := WithCerts("", "")
	option := certs.(*certsOption)
	assert.Nil(t, option.certs[0].Certificate)
}
